use std::{env, fs};
use pest::{error::{LineColLocation}, Parser};
use pest_derive::Parser;

#[derive(Parser)]
#[grammar = "lexer.pest"] // 指向你的 .pest 文件
struct EParser;

// #[derive(Parser)]
// #[grammar = "test.pest"]
// pub struct EParser;

// #[derive(Debug, PartialEq)]
// pub enum Token {
//     Integer(i64),
//     Operator(char),
// }

// pub fn tokenize(input: &str) -> Vec<Token> {
//     let pair = ExpressionParser::parse(Rule::TOKEN, input)
//         .unwrap_or_else(|e| panic!("Parse error: {}", e))
//         .next()
//         .unwrap(); // 取第一个匹配

//     pair.into_inner()
//         .map(|p| match p.as_rule() {
//             Rule::INT => Token::Integer(p.as_str().parse().unwrap()),
//             Rule::op => Token::Operator(p.as_str().chars().next().unwrap()),
//             _ => unreachable!(),
//         })
//         .collect()
// }

fn main() {
    // 收集命令行参数
    let args: Vec<String> = env::args().collect();
    // 检查是否提供了文件名
    if args.len() < 2 {
        eprintln!("Usage: {} <filename>", args[0]);
        std::process::exit(1);    }
    // 获取文件名
    let filename = &args[1];
    // if filename.contains("NormalTest5.sy"){
    //     panic!("{:?}",fs::read_to_string(&filename).unwrap());
    // }
    // 读取输入文件
    // let input = fs::read_to_string("/home/arthur/gitrepos/compiler1/compiler/src/input.txt").expect("Failed to read file");
    let input = fs::read_to_string(&filename).expect("Failed to read file");
    // 词法分析
    // let tokens = tokenize(&input);

    // // // print tokens
    // let parse_result = EParser::parse(Rule::file, &input).unwrap();
    // let tokens = parse_result.tokens();
    // for token in tokens {
    //     println!("{:?}", token);
    // }

    // let pairs = EParser::parse(Rule::file, &input)
    //     .unwrap().next().unwrap()
    //     .into_inner();

    match EParser::parse(Rule::file, &input){
        Ok(pairs) => {
            // println!("{:?}", pairs);
            pairs.clone().for_each(|p| 
                // println!("{:?} {} at line {} column {}", 
                // p.as_rule(), p.as_str() ,p.line_col().0, p.line_col().1));
                p.into_inner().for_each(|pp| 
                    {
                        // println!(">>>{:?} {} at line {} column {}", 
                        //     pp.as_rule(), pp.as_str() ,pp.line_col().0, pp.line_col().1)
                        
                        pp.into_inner().for_each(|ppp| {
                            let as_rule = ppp.as_rule();
                            let as_str = ppp.as_str();
                            let val = as_str;
                            if let Rule::INTEGER_CONST = as_rule.clone() {
                                let mut val = 0;
                                if as_str.starts_with("0x") || as_str.starts_with("0X") {
                                    // println!("=======");                                    
                                    let as_str_as_int: usize = usize::from_str_radix(&as_str[2..], 16).unwrap();
                                    val = as_str_as_int;
                                    eprintln!("{:?} {} at Line {}.", 
                                        ppp.as_rule(), val ,ppp.line_col().0)
                                }else if as_str.starts_with("0b") {
                                    // println!("=======");                                    
                                    let as_str_as_int: usize = usize::from_str_radix(&as_str[2..], 2).unwrap();
                                    val = as_str_as_int;
                                    eprintln!("{:?} {} at Line {}.", 
                                        ppp.as_rule(), val ,ppp.line_col().0)
                                }else if as_str.starts_with("0") {
                                    let as_str_as_int: usize = usize::from_str_radix(&as_str, 8).unwrap();
                                    val = as_str_as_int;
                                    eprintln!("{:?} {} at Line {}.", 
                                        ppp.as_rule(), val ,ppp.line_col().0)
                                }else{
                                    eprintln!("{:?} {} at Line {}.", 
                                        ppp.as_rule(), as_str ,ppp.line_col().0)
                                }                                
                            // }else if let Rule::ERR = as_rule {
                            //     eprintln!("Error type A at Line {:?}: Unable to understand '{}'", ppp.line_col().0, as_str);
                            }else{
                                eprintln!("{:?} {} at Line {}.", 
                                    ppp.as_rule(), val ,ppp.line_col().0)
                            }
                            
                        });
                    }
                ));
        }
        Err(e) => {
            // eprintln!("Error type {:?} at Line {:?}",  e.variant.type_id(), e.line_col );
            let mut lineno:usize = 0 ;
            match e.line_col {
                LineColLocation::Pos((y,_z)) => {lineno = y},
                LineColLocation::Span((_y,_z),(_y2,_z2)) => {}
            }
            // if let LineColLocation::Pos((y,z)) = e.line_col;
            // eprintln!("Error type {} at line {:?}:{}", e.variant.message(),lineno,e.variant.message());
            eprintln!("Error type A at Line {:?}:{}", lineno,e.variant.message());
        },
    }


    // let numbers = pairs
    //     .clone()
    //     .map(|pair| {println!("{:?}", pair);str::parse(pair.as_str()).unwrap()})
    //     .collect::<Vec<i32>>();

    // // assert_eq!(vec![1773, 1362], numbers);
    // eprintln!("{:?}===",numbers);

    // for (found, expected) in pairs.zip(vec!["1232", "6786"]) {
    // // for (found, expected) in pairs {
    //     println!("{:?}-->{:?}",Rule::number, found.as_rule());
    //     println!("expected==>{:?}-->{}", expected, found.as_str());
    // }
    // pairs.clone().for_each(|p| println!("{:?} {} at line {} column {}", 
        // p.as_rule(), p.as_str() ,p.line_col().0, p.line_col().1));
}

// INT int at Line 1.
// IDENT main at Line 1.
// L_PAREN ( at Line 1.
// R_PAREN ) at Line 1.
// L_BRACE { at Line 2.
// Error type A at Line [lineNo]:[errorMessage]